package com.google.code.jerseyclients.asynchttpclient;

/*
 * Olivier Lamy
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

import javax.ws.rs.ext.Providers;

import com.google.code.jerseyclients.JerseyHttpClientConfig;
import com.ning.http.client.AsyncHttpClient;
import com.ning.http.client.AsyncHttpClientConfig.Builder;
import com.ning.http.client.ProxyServer;
import com.ning.http.client.providers.netty.NettyAsyncHttpProvider;
import com.ning.http.client.providers.netty.NettyConnectionsPool;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.core.spi.component.ioc.IoCComponentProviderFactory;

/**
 * created 1 oct. 2010
 * 
 * @author <a href="mailto:olamy@apache.org">Olivier Lamy</a>
 * @version $Id: AsyncHttpClientJerseyClient.java 15 2011-02-28 15:35:12Z oliver.lamy $
 */
public class AsyncHttpClientJerseyClient
    extends Client
{

    private AsyncHttpClientJerseyClientHandler clientHandler;

    /**
     * Create a new client instance.
     * 
     * @param root the root client 
     */
    public AsyncHttpClientJerseyClient( AsyncHttpClientJerseyClientHandler root )
    {
        this( root, new DefaultClientConfig(), null );
    }

    /**
     * Create a new client instance with a configuration.
     * 
     * @param root the root client
     * @param config client configuration.
     */
    public AsyncHttpClientJerseyClient( AsyncHttpClientJerseyClientHandler root, ClientConfig config )
    {
        this( root, config, null );
    }

    /**
     * @param root the root client handler for dispatching a request and returning a response.
     * @param config the client configuration.
     * @param provider the IoC component provider factory.
     */
    public AsyncHttpClientJerseyClient( AsyncHttpClientJerseyClientHandler root, ClientConfig config,
                                       IoCComponentProviderFactory provider )
    {
        super( root, config, provider );

        this.clientHandler = root;
    }

    /**
     * 
     * @return AsyncHttpClient handler.
     */
    public AsyncHttpClientJerseyClientHandler getClientHandler()
    {
        return clientHandler;
    }

    /**
     * Create a default client.
     * 
     * @return a default client.
     */
    public static AsyncHttpClientJerseyClient create( JerseyHttpClientConfig config )
    {
        return new AsyncHttpClientJerseyClient( createDefaultClientHander( config ) );
    }

    /**
     * Create a default client with client configuration and component provider.
     * 
     * @param cc the client configuration.
     * @param provider the IoC component provider factory.
     * @return a default client.
     */
    protected static AsyncHttpClientJerseyClient create( ClientConfig cc, IoCComponentProviderFactory provider,
                                                        JerseyHttpClientConfig config )
    {
        return new AsyncHttpClientJerseyClient( createDefaultClientHander( config ), cc, provider );
    }

    /**
     * Create a default Apache HTTP client handler.
     * 
     * @return a default Apache HTTP client handler.
     */
    public static AsyncHttpClientJerseyClientHandler createDefaultClientHander( JerseyHttpClientConfig config )
    {
        Builder builder = new Builder();
        builder.setConnectionTimeoutInMs( config == null ? 60000 : config.getConnectionTimeOut() );
        builder.setRequestTimeoutInMs( config.getReadTimeOut() );
        builder.setFollowRedirects( true );
        builder.setKeepAlive( config.isReuseConnection() );
        builder.setMaximumConnectionsTotal( config.getMaxConnections() );
        builder.setMaximumConnectionsPerHost( config.getMaxConnectionsPerHost() );
        builder.setIdleConnectionTimeoutInMs( config.getIdleConnectionTimeout() );
                
        if ( config.getProxyInformation() != null )
        {
            ProxyServer proxyServer = new ProxyServer( config.getProxyInformation().getProxyHost(), config
                .getProxyInformation().getProxyPort() );
            builder.setProxyServer( proxyServer );
        }
        
        NettyAsyncHttpProvider nettyAsyncHttpProvider = new NettyAsyncHttpProvider( builder.build() );
        
        NettyConnectionsPool nettyConnectionsPool = new NettyConnectionsPool( nettyAsyncHttpProvider );
        
        builder.setConnectionsPool( nettyConnectionsPool );
        
        AsyncHttpClient asyncHttpClient = new AsyncHttpClient( builder.build() );
        return new AsyncHttpClientJerseyClientHandler( asyncHttpClient, config );
    }

    @Override
    public Providers getProviders()
    {
        Providers providers = super.getProviders();

        return providers;
    }
}
